package vv.lines.core;

import java.util.*;

import static vv.lines.core.Orientation.*;

/**
 * @author vpotapenko
 */
public class CellHolder {

    private static final Map<Orientation, Map<Boolean, Integer>> colTransformer =
            new HashMap<Orientation, Map<Boolean, Integer>>();
    private static final Map<Orientation, Map<Boolean, Integer>> rowTransformer =
            new HashMap<Orientation, Map<Boolean, Integer>>();
    static {
        Map<Boolean, Integer> part = new HashMap<Boolean, Integer>();
        part.put(false, 0);
        part.put(true, 0);
        colTransformer.put(VERTICAL, part);

        part = new HashMap<Boolean, Integer>();
        part.put(false, -1);
        part.put(true, 1);
        colTransformer.put(HORIZONTAL, part);
        colTransformer.put(FDIAGONAL, part);
        colTransformer.put(BDIAGONAL, part);

        part = new HashMap<Boolean, Integer>();
        part.put(false, 0);
        part.put(true, 0);
        rowTransformer.put(HORIZONTAL, part);

        part = new HashMap<Boolean, Integer>();
        part.put(false, -1);
        part.put(true, 1);
        rowTransformer.put(VERTICAL, part);
        rowTransformer.put(FDIAGONAL, part);

        part = new HashMap<Boolean, Integer>();
        part.put(false, 1);
        part.put(true, -1);
        rowTransformer.put(BDIAGONAL, part);
    }

    private Cell[][] cells;

    public CellHolder(Field field, int columnCount, int rowCount) {
        initCells(field, columnCount, rowCount);
        initPeers();
    }

    public Cell getPeerCell(int column, int row, Orientation orientation, boolean ascend) {
        column += colTransformer.get(orientation).get(ascend);
        row += rowTransformer.get(orientation).get(ascend);

        return getCell(column, row);
    }

    private void initCells(Field field, int columnCount, int rowCount) {
        cells  = new Cell[columnCount][rowCount];
        for (int col = 0; col < columnCount; col++) {
            for (int row = 0; row < rowCount; row++) {
                Cell cell = new Cell(field.getContext(), col, row);
                cell.setField(field);

                cells[col][row] = cell;
            }
        }
    }

    private void initPeers() {
        for (int col = 0; col < getColumnCount(); col++) {
            for (int row = 0; row < getRowCount(); row++) {
                initPeersForCell(cells[col][row]);
            }
        }
    }

    private void initPeersForCell(Cell cell) {
        HashSet<Cell> peers = new HashSet<Cell>();

        Cell peer = getCell(cell.getColumn() - 1, cell.getRow());
        if (peer != null) peers.add(peer);

        peer = getCell(cell.getColumn(), cell.getRow() - 1);
        if (peer != null) peers.add(peer);

        peer = getCell(cell.getColumn() + 1, cell.getRow());
        if (peer != null) peers.add(peer);

        peer = getCell(cell.getColumn(), cell.getRow() + 1);
        if (peer != null) peers.add(peer);

        cell.setPeers(peers);
    }

    private boolean isValidCell(int column, int row) {
        return (column >= 0) && (row >= 0) && (column < getColumnCount()) &&
                (row < getRowCount());
    }

    public boolean hasFreeCells() {
        return getFreeCells().size() > 0;
    }

    public void clearAll() {
        for (int col = 0; col < getColumnCount(); col++) {
            for (int row = 0; row < getRowCount(); row++) {
                getCell(col, row).setBall(null);
            }
        }
    }

    public List<Cell> getFreeCells() {
        List<Cell> freeCells = new ArrayList<Cell>();
        for (int col = 0; col < getColumnCount(); col++) {
            for (int row = 0; row < getRowCount(); row++) {
                Cell cell = cells[col][row];
                if (cell.getBall() == null) {
                    freeCells.add(cell);
                }
            }
        }

        return freeCells;
    }

    public void updateCellsBounds(int fieldWidth, int fieldHeight) {
        if (getColumnCount() == 0 || getRowCount() == 0) return;

        int x = 0;
        int y = 0;
        int width = fieldWidth / getRowCount();
        int height = fieldHeight / getColumnCount();

        for (int col = 0; col < getColumnCount(); col++) {
            for (int row = 0; row < getRowCount(); row++) {
                Cell cell = cells[col][row];

                cell.setLocation(x, y);
                cell.setSize(width, height);
                cell.setVisible(true);

                x += width;
            }
            x = 0;
            y += height;
        }
    }

    public Cell getCell(int column, int row) {
        return isValidCell(column, row) ? cells[column][row] : null;
    }

    public int getColumnCount() {
        return cells != null ? cells.length : 0;
    }

    public int getRowCount() {
        return getColumnCount() > 0 ? cells[0].length : 0;
    }
}
